package org.fastsyncer.manager.driver.impl;

import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

import org.fastsyncer.common.DefaultThreadFactory;
import org.fastsyncer.common.constant.EventConstant;
import org.fastsyncer.manager.driver.Event;
import org.fastsyncer.manager.driver.Subject;

/**
 * 驱动事件:
 * <p>基于观察者模式设计实现,驱动事件类型:1.新增、2.修改、3.删除、4.启动、5.停止、6.启用、7.禁用</p>
 * 
 * <p>如何使用：继承<tt>AbstractDriverEvent</tt>接口,重写你需要监听的事件方法, 例如：</p>
 * <pre>
 *  public class Hello extends AbstractDriverEvent {                  
 * 
 *  //@Override
 *  public void add(String id) {
 *      System.out.println("这是Hello里面的add方法" + id);
 *  }
 * 
 *  //@Override
 *  public void update(String id) {
 *      System.out.println("这是Hello里面的update方法" + id);
 *  }
 *  
 *  ...
 *  
 * }
 * </pre>
 * 
 * @author AE86
 * @date 2017年12月14日 下午10:16:12
 * @version 1.0.0
 */
public abstract class AbstractDriverEvent implements Subject, Event {

    // 定义事件请求处理队列,并发默认30
    private static final BlockingQueue<EventMsg> QUENE = new LinkedBlockingQueue<>(30);

    // 缓存观察者对象
    private static final List<Event> OBSERVERS = new CopyOnWriteArrayList<Event>();

    // 通知线程池
    private static final ExecutorService EXECUTOR = Executors.newCachedThreadPool(new DefaultThreadFactory("DriverEvent-threadpool"));
    
    @Override
    public void addObserver(Event e) {
        if (null == e) {
            return;
        }
        OBSERVERS.add(e);
    }

    @Override
    public void removeObserver(Event e) {
        if (null == e) {
            return;
        }
        OBSERVERS.remove(e);
    }

    @Override
    public void add(String id) {

    }

    @Override
    public void update(String id) {

    }

    @Override
    public void delete(String id) {

    }

    @Override
    public void start(String id) {

    }

    @Override
    public void stop(String id) {

    }

    @Override
    public void enable(String id) {

    }

    @Override
    public void disable(String id) {

    }

    /**
     * 分类处理事件方法
     * @param m
     */
    private void handle(EventMsg m) {
        final String event = m.getEvent();
        final String id = m.getId();
        final int size = OBSERVERS.size();
        Event e = null;
        for (int i = 0; i < size; i++) {
            e = OBSERVERS.get(i);
            switch (event) {
            case EventConstant.ADD:
                e.add(id);
                break;
            case EventConstant.UPDATE:
                e.update(id);
                break;
            case EventConstant.DELTED:
                e.delete(id);
                break;
            case EventConstant.START:
                e.start(id);
                break;
            case EventConstant.STOP:
                e.stop(id);
                break;
            case EventConstant.ENABLE:
                e.enable(id);
                break;
            case EventConstant.DISABLE:
                e.disable(id);
                break;
            default:
                break;
            }
        }
    }

    /**
     * 通知注册事件的观察者们
     * <pre>
     *  由于注册的观察者可能会有很多,如果在同一时间等待观察者们完成事件处理,那么前端会一直处于
     *  等待响应或阻塞状态,同时事件还在频繁触发,系统可用资源会急剧下降.为防止这个问题发生,这
     *  里采用异步调用去触发事件,将事件存放至消息队列,并且限制消息队列并发请求数,超过系统请求
     *  直接拒绝或抛出异常.
     * </pre>
     * @param e 事件类型
     * @param id 驱动ID
     */
    @Override
    public void notice(String event, String id) {
        // 1.定义事件消息体, 添加事件到队列中
        QUENE.offer(new EventMsg(event, id));

        // 2.触发通知
        notice();
    }
    
    private void notice(){
        if(!QUENE.isEmpty()){
            // 1.异步处理消息队列事件
            CompletableFuture.supplyAsync(() -> {
                while (!QUENE.isEmpty()) {
                    try {
                        this.handle(QUENE.poll());
                    } catch (Exception ex) {
                        continue;
                    }
                }
                return true;
            }, EXECUTOR).whenComplete((v, e) -> {
                // 2.处理刚结束的时候，队列正好有新的事件，为保证队列中的事件完全被处理掉，再次调用notice方法继续处理，直到为空
                if(!QUENE.isEmpty()){
                    notice();
                }
            });
        }
    }

    class EventMsg {
        
        String event;

        String id;

        public EventMsg(String event, String id) {
            super();
            this.event = event;
            this.id = id;
        }

        public String getEvent() {
            return event;
        }

        public String getId() {
            return id;
        }
        
    }
    
}
